package net.lastcoder.ifserver.packet;

import net.lastcoder.ifserver.Constants;
import net.lastcoder.ifserver.session.UlaID;
import net.lastcoder.ifserver.util.DataTypeUtil;

import org.json.JSONException;
import org.json.JSONObject;

/**注意有些event type 值已经使用<br>
 * ZONE_EVENT_TYPE = 0x0001;<br>
 * ROOM_EVENT_TYPE = 0x0001;<br>
 * PING_EVENT_TYPE = 0x0001;<br>
 * auth: WenYF
 * date: 2016/9/29
 */
public class Event extends Packet {
    public static final short PING_EVENT_TYPE = 0x0010;

    // 区别不同的event type, 1 和 2 已经使用
    short eventType;
    byte type;
    protected int actionCode;
    private byte[] body = new byte[0];
    /**
     * @param eventType 如果为0，该eventType无效，将没有handler与之对应，一般在投递给指定的node使用
     * @param type
     * @param actionCode 为0表示没有action
     */
    public Event(short eventType, byte type, int actionCode) {
        this.eventType = eventType;
        this.type = type;
        this.actionCode = actionCode;
    }

    public void setType(byte type) {
        this.type = type;
    }

    public int getActionCode() {
        return actionCode;
    }

    public void setActionCode(int actionCode) {
        this.actionCode = actionCode;
    }

    public String getBody() {
        return body == null ? "" : new String(body, charset);
    }

    public byte[] getRawBody() {
        return body;
    }

    public void setBody(String body) {
        setBody(body.getBytes(charset));
    }

    public void setBody(byte[] body) {
        this.body = body;
    }

    @Override
    public void setFromAddress(UlaID ulaid) {
        fromUlaID = ulaid;
    }

    @Override
    protected byte[] getContent(boolean isBinary) {
        if (isBinary) {
            return getBinary();
        } else {
            return getJson();
        }
    }

    private byte[] getJson(){
        JSONObject json = new JSONObject();
        try {
            json.put("type", type);
            json.put("eventType", eventType);
            json.put("actionCode", getActionCode());
            json.put("body", getBody());
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return json.toString().getBytes();
    }

    private byte[] getBinary() {
        byte[] eventTypeBytes = DataTypeUtil.shortToByteArray(eventType);
        byte[] actionCodeBytes = DataTypeUtil.intToByteArray(getActionCode());
        byte[] bodyBytes = getRawBody();

        byte[] content = new byte[eventTypeBytes.length + 1 + 4 + 4 + bodyBytes.length];
        int count = 0, i;
        for (i = 0; i < eventTypeBytes.length && count < content.length; i ++, count ++) {
            content[count] = eventTypeBytes[i];
        }
        content[count++] = type;
        // action code
        for (i = 0; i < actionCodeBytes.length && count < content.length; i ++, count ++) {
            content[count] = actionCodeBytes[i];
        }

        // content data
        byte[] lengthBytes = DataTypeUtil.intToByteArray(bodyBytes.length);
        for (i = 0; i < lengthBytes.length && count < content.length; i ++, count ++) {
            content[count] = lengthBytes[i];
        }
        for (i = 0; i < bodyBytes.length && count < content.length; i ++, count ++) {
            content[count] = bodyBytes[i];
        }
        return content;
    }

    @Override
    public byte getPacketType() {
        return Constants.PACKET_TYPE_EVENT;
    }

    public short getEventType() {
        return eventType;
    }

    public byte getType() {
        return type;
    }

    public Event createResult() {
        Event event = new Event(eventType, TYPE_RESULT, actionCode);
        event.setFromAddress(getToAddress());
        event.setToAddress(getFromAddress());
        event.setId(getId());
        return event;
    }

    public Event createError() {
        Event event = new Event(eventType, TYPE_ERROR, actionCode);
        event.setFromAddress(getToAddress());
        event.setToAddress(getFromAddress());
        event.setId(getId());
        return event;
    }

    @Override
    public String toString() {
        return super.toString() + ", Event{" +
                "eventType=" + eventType +
                ", type=" + type +
                ", actionCode=" + actionCode +
                ", body=" + getBody() +
                '}';
    }
}
